package cn.achao.csr.chat.service.wx;

import cn.achao.csr.api.SequenceApi;
import cn.achao.csr.api.model.dto.LoginMessageDTO;
import cn.achao.csr.api.model.dto.ScanSuccessMessageDTO;
import cn.achao.csr.api.model.entity.ChatUser;
import cn.achao.csr.base.constant.Constants;
import cn.achao.csr.base.constant.RedisKeyConstants;
import cn.achao.csr.base.constant.RockMqKeyConstants;
import cn.achao.csr.base.constant.SecurityConstants;
import cn.achao.csr.chat.core.build.TextAdapter;
import cn.achao.csr.chat.core.build.UserAdapter;
import cn.achao.csr.chat.dao.ChatUserDao;
import cn.achao.csr.chat.service.ChatUserService;
import cn.achao.csr.mq.producer.CsrMqProducer;
import cn.achao.csr.redis.service.RedisService;
import cn.hutool.core.util.RandomUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author: achao
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class WxMsgServiceImpl {

    /**
     * 用户的openId和前端登录场景code的映射关系
     */
    private static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
    @Value("${wx.mp.callback}")
    private String callback;

    private final SequenceApi sequenceApi;

    private final ChatUserDao userDao;
    private final CsrMqProducer mqProducer;
    private final RedisService redisService;
    private final ChatUserService userService;

    public WxMpXmlOutMessage scan(WxMpService wxMpService, WxMpXmlMessage wxMpXmlMessage) {
        String openid = wxMpXmlMessage.getFromUser();
        Long loginCode = Long.valueOf(getEventKey(wxMpXmlMessage));
        log.info("有人扫码了,游客编码{}", loginCode);
        ChatUser user = userDao.getByOpenId(openid);
        //如果已经注册,直接登录成功
        if (Objects.nonNull(user) && StringUtils.isNotEmpty(user.getAvatarUrl())) {
            mqProducer.sendMsg(RockMqKeyConstants.LOGIN_MSG_TOPIC, new LoginMessageDTO(user.getId(), loginCode));
            return null;
        }

        //在redis中保存openid和场景code的关系，后续才能通知到前端,旧版数据没有清除,这里设置了过期时间
        redisService.setCacheObject(RedisKeyConstants.getKey(RedisKeyConstants.OPEN_ID_STRING, openid), loginCode, 60L, TimeUnit.MINUTES);
        String skipUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/csr-chat/wx/portal/public/callBack"));
        WxMpXmlOutMessage.TEXT().build();
        return new TextAdapter().build("请点击链接授权：<a href=\"" + skipUrl + "\">登录</a>", wxMpXmlMessage, wxMpService);
    }

    private String getEventKey(WxMpXmlMessage wxMpXmlMessage) {
        //扫码关注的渠道事件有前缀，需要去除
        return wxMpXmlMessage.getEventKey().replace("qrscene_", "");
    }

    /**
     * 用户授权
     *
     * @param userInfo
     */
    public void authorize(WxOAuth2UserInfo userInfo) {
        ChatUser user = userDao.getByOpenId(userInfo.getOpenid());
        if (user == null) {
            user = UserAdapter.buildUser(userInfo);
            userService.register(user);
        }

        //找到对应的code
        Long code = redisService.getCacheObject(RedisKeyConstants.getKey(RedisKeyConstants.OPEN_ID_STRING, userInfo.getOpenid()), Long.class);
        //发送登录成功事件
        mqProducer.sendMsg(RockMqKeyConstants.LOGIN_MSG_TOPIC, new LoginMessageDTO(user.getId(), code));
    }
}
